什麼是單例模式(Singleton pattern)?
單例確保類別(class)只存在一個實例,且該實例就像全域變數一般,可被同程式的任何人訪問。
解決的問題:
C++範例:
class Singleton
{
public:
// 使用者透過呼叫GetInstance取得類別的實例
// 注意此類別的ctor已移至private,防止使用者自行創建實例
static Singleton *GetInstance()
{
// 首次呼叫會創建實體,後續的呼叫則回傳已創建實例的指標
if (obj == nullptr)
obj = new Singleton();
return obj;
}
void DoSomething()
{
//...
}
private:
static Singleton *obj;
Singleton() {}
};
Singleton *Singleton::obj = nullptr;
// 類別使用方法
int main()
{
// 呼叫GetInstance獲取實例
Singleton *instance = Singleton::GetInstance();
instance->DoSomething();
}
對於多線程程式,上述的Singleton範例並不是thread-safe。假設線程A 通過了上述的if (obj == nullptr)
,準備要執行obj = new Singleton();
,此時若線程B 也剛好通過了if (obj == nullptr)
,則將會有兩個實例被創建,這不是我們想要的。
對於此問題,Scott Meyers的Effective C++一書提到,可利用local static object在第一次被呼叫使用才初始化的特性來優化:
class Singleton
{
public:
static Singleton &GetInstance()
{
// obj是local static object,在第一次被創建後,之後不
// 管再進來幾次,都會跳過創建的流程而返回已創建的實例
static Singleton obj;
return obj;
}
void DoSomething()
{
//...
}
private:
Singleton();
};
// 類別使用方法
int main()
{
Singleton &instance = Singleton::GetInstance();
instance.DoSomething();
}
以上範例在C++11後是保證thread-safe。